import json
import gradio as gr
from openai import OpenAI
import threading
from datetime import datetime
import uuid  # 可选：用于生成唯一会话ID

data = []

#以下为声明全局变量
ver="0.4" #版本号
apikey = "在这输入你的apikey" # 你的API密钥
api_url = "https://api.deepseek.com" #模型调用地址

sp1 = "你是一个服务于空间粒子探测方向科研人员的人工智能，帮助他们进行粒子物理及天文方向科研工作的人工智能助手,你会用精炼的语言准确易懂的回答用户所提提出的各种问题,但不能编造、预测和改编你不知道的信息！不知道就说不知道！忽略prompt中的html标记不要擅自输出！"

#以下为css与html
mycss = """
/* 隐藏Gradio页脚 */
footer {visibility: hidden}

.gradio-container {
  background-color: #FFFFFF;
        font-family: Arial, sans-serif;
  /* 设置边框为10px宽的实线，颜色为淡灰色 */
  border: 2px solid #DDDDDD;
  /* 给容器添加圆角边框，半径为10px */
  border-radius: 13px;
  /* 在容器内容和边框之间添加20px的填充 */
  padding: 1px;
}
/* 头像绿 */
#button1 {
  background-color:#9FED04
}
/* 头像灰 */
#button2 {
  background-color:#E2DDDA
}
/* 头像紫 */
#button3 {
  background-color:#B72C89
}

#欢迎页 {
  background-color: #ffffff
}
#欢迎页-button {
  background-color: #ffffff
}





"""

dengluhtml="""
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>登录页</title>
    <style>
        .text-content {
            text-align: center;
            h1 {
            font-size: 50px;
            color: #007BFF;
            font-family: 'STCAIYUN', '微软雅黑', sans-serif;
            }
            p {
            font-size: 19px;
            font-family: 'STXINGKA', sans-serif;
            }
        }
        .center-table {
            margin-top: 0px; /* 调整数值以控制上边距 */
            margin-bottom: 2px; /* 调整数值以控制下边距 */
            margin: 0 auto; /* 表格自身居中 */
            width: 20%; /* 可调整表格宽度 */
        }
    </style>
</head>
<body>
    <table class="center-table">
    <tr>
    <td>
        <img src="" alt="logo头图" style="display: block; margin: auto;">
    </td>
    </tr>
    </table>
    <div class="text-content">
        <h1>大语言模型调用器--特别精简版</h1>
        <p>٩(͡๏̯͡๏)۶</p>
        <p>一个支持用户自定义对话和知识库的人工智能科研助理</p>
    </div>
</body>
</html>

"""

#gradio主题色调设置
mytheme = gr.themes.Monochrome(
    primary_hue=gr.themes.Color(c100="#f3f4f6", c200="#e5e7eb", c300="#6b7280", c400="#9ca3af", c50="#f9fafb",c500="#6b7280", c600="#4b5563", c700="#374151", c800="#1f2937", c900="#111827",c950="#0b0f19"),   # 自定义主色
    #secondary_hue=gr.themes.Color(c100="#f3f4f6", c200="#e5e7eb", c300="#6b7280", c400="#9ca3af", c50="#f9fafb",c500="#6b7280", c600="#4b5563", c700="#374151", c800="#1f2937", c900="#111827",c950="#0b0f19"),
    secondary_hue="slate",   # 自定义次色
    neutral_hue=gr.themes.Color(c100="#f3f4f6", c200="#e5e7eb", c300="#d1d5db", c400="#9ca3af", c50="#f9fafb", c500="#6b7280", c600="#4b5563", c700="#374151", c800="#1f2937", c900="#4f4f4f", c950="#0b0f19"),    # 自定义中性色
    spacing_size="md",
    radius_size="sm",
    font=['Source Sans Pro', 'ui-sans-serif', 'system-ui', 'sans-serif']).set(
    body_text_weight='500',
    block_border_width='2px',
    block_border_width_dark='2px',
    block_info_text_size='*text_lg',
    )
#以下为大模型提示词
prompt0=[
        {"role": "system", "content": sp1},
]

def mima(username, password):
    if username == "test1" and password == "123456":
        return 1
    if username == "test2" and password == "1234":
        return 1
    if username == "test3" and password == "mima123":
        return 1
    if username == "1" and password == "1":
        return 1
    if username == "mima" and password == "123456":
        return 1
    else:
        return 0
def tag(history_state):
    history_state["prompt"] = [
        {"role": "system", "content": sp1 },
    ]
    #print(history_state)
    return history_state, []

def init_history():
    return {
        "chat": [],
        "id": str(uuid.uuid4()),
        "prompt": [
        {"role": "system", "content": sp1},
        ],
        "file_btn": None
    }

#gradio转化为history
def convert_prompt_to_history(prompt):
    history = []
    current_user_message = None

    for msg in prompt:
        if msg["role"] == "system":
            continue  # 跳过系统消息

        if msg["role"] == "user":
            current_user_message = msg["content"]
        elif msg["role"] == "assistant" and current_user_message is not None:
            history.append([current_user_message, msg["content"]])
            current_user_message = None  # 重置等待下一个用户消息

    return history

#反向转换
def history_to_prompt(history):
    converted = [
        {"role": "system", "content": sp1},
]
    for user_msg, assistant_msg in history:
        converted.append({"role": "user", "content": user_msg})
        if assistant_msg is not None:
            converted.append({"role": "assistant", "content": assistant_msg})

    return converted

def createfile(history_state):  # 新增history_state参数
    #print(history_state)
    timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
    custom_name = f"DEEPSEEK记忆_{timestamp}.card"
    with open(custom_name, "w", encoding="utf-8") as f:
        json.dump(history_state["prompt"], f, ensure_ascii=False, indent=4)
    history_state["file_btn"] = custom_name
    return custom_name, history_state

def get_latest_file(history_state):
    print(history_state["file_btn"])
    return history_state["file_btn"]  # 直接返回记忆卡文件路径

def read(filename, history_state):  # 新增history_state参数
    with open(filename, "r", encoding="utf-8") as f:
        new_prompt = json.load(f)
        history_state["prompt"] = new_prompt
        history = convert_prompt_to_history(new_prompt)
    return "", history

def user(user_message, history, history_state):
    user_id = history_state["id"]
    gg1 = f"您好，本次的唯一性识别码为：{user_id}，欢迎您使用！"
    return "", history + [[user_message, None]], history_state, gg1
def deepseekr1(history, history_state):
    prompt = history_state["prompt"]
    api_key = apikey
    client = OpenAI(api_key=api_key, base_url=api_url)
    last1 = history[-1][0]
    add1 = {"role": "user", "content": last1}
    prompt.append(add1)
    print(prompt)
    messages = prompt.copy()
    response = client.chat.completions.create(
        model="deepseek-reasoner",
        messages=messages,
        stream=True
    )
    # print("回答：\n")
    history[-1][1] = ""
    tag1 = 0
    tag2 = 0
    for event in response:
        if event.choices[0].delta.reasoning_content:
            if tag1 == 0:
                history[-1][1] += '<span style="color: blue; font-family: Consolas;">思考过程：</span>\n\n'
            history[-1][1] += event.choices[0].delta.reasoning_content
            # time.sleep(0.001)
            yield history, history_state
            # print(event.choices[0].delta.content, end="")
            tag1 += 1
        elif event.choices[0].delta.content:
            if tag2 == 0:
                history.append([None, ''])
                history[-1][1] += '<span style="color: red; font-family: Consolas;">输出结果：</span>\n\n'
            history[-1][1] += event.choices[0].delta.content
            # time.sleep(0.001)
            yield history, history_state
            #print(event.choices[0].delta.content, end="")
            tag2 += 1
    last2 = history[-1][1]
    #print(last2)
    add2 = {"role": "assistant", "content": last2}
    prompt.append(add2)

    history_state["prompt"] = prompt
    yield history, history_state
def deepseekv3(history):
    global prompt

    api_key = apikey
    client = OpenAI(api_key=api_key, base_url=api_url)
    last1 = history[-1][0]
    add1 = {"role": "user", "content": last1}
    prompt.append(add1)
    print(prompt)
    messages = prompt
    response = client.chat.completions.create(
        model="deepseek-reasoner",
        messages=messages,
        stream=True
    )
    # print("回答：\n")
    history[-1][1] = ""
    tag1 = 0
    tag2 = 0
    for event in response:
        if event.choices[0].delta.reasoning_content:
            if tag1 == 0:
                history[-1][1] += '<span style="color: blue; font-family: Consolas;">思考过程：</span>\n\n'
            history[-1][1] += event.choices[0].delta.reasoning_content
            # time.sleep(0.001)
            yield history
            # print(event.choices[0].delta.content, end="")
            tag1 += 1
        elif event.choices[0].delta.content:
            if tag2 == 0:
                history[-1][1] += '\n\n<span style="color: red; font-family: Consolas;">输出结果：</span>\n\n'
            history[-1][1] += event.choices[0].delta.content
            # time.sleep(0.001)
            yield history
            # print(event.choices[0].delta.content, end="")
            tag2 += 1
            if event.choices[0].finish_reason == "stop":
                i = event.usage.total_tokens
    last2 = history[-1][1]
    add2 = {"role": "assistant", "content": last2}
    prompt.append(add2)


with gr.Blocks(theme=mytheme,title="deepseek调用器",css=mycss) as demo:
    # 隔离
    history_state = gr.State()

    # 初始化
    demo.load(init_history, outputs=[history_state], queue=False)

    #enable_api = False    #字面意思
    gr.Markdown("# 大语言模型调用器精简版")
    gr.Markdown("###    一个专业调用大语言模型且支持用户自定义对话和知识库的独立模块")
    #gr.Markdown("### 您好，欢迎您的使用！")
    # title可以修改页面标题
    with gr.Tab('DEEPSEEK-r1'):
        gg1 = gr.Textbox(label="系统公告栏（面向用户）", value="尊敬的用户您好，欢迎您使用！请开始对话以获取您本次的唯一性识别码！")
        chatbot = gr.Chatbot(label="对话界面")
        msg = gr.Textbox(label="用户输入框")
        submit_button41 = gr.Button("提交", variant="primary")
        clear_button42 = gr.Button("清除")
        with gr.Row():
            with gr.Column():
                jy1 = gr.File(type="filepath", label="输入记忆卡")
            with gr.Column():
                x1 = gr.Textbox(label="系统提示词（不支持普通用户修改）", value=sp1)
                submit_button01 = gr.Button("应用记忆（先在左侧上传记忆卡）")
                submit_button02 = gr.DownloadButton("异步下载保存本次记忆(点击下载的是上一次点击后的记忆)")
        msg.submit(user, [msg, chatbot, history_state], [msg, chatbot, history_state, gg1], queue=False).then(deepseekr1, [chatbot, history_state], [chatbot, history_state])
        submit_button01.click(read, [jy1, history_state], [msg, chatbot], queue=False)
        #submit_button02.click(fn=createfile, outputs=submit_button02, _js="(filePath) => {const link = document.createElement('a');link.href = filePath;link.download = '';document.body.appendChild(link);link.click();document.body.removeChild(link);return [];}")
        submit_button02.click(fn=createfile, inputs=history_state, outputs=[submit_button02, history_state], queue=False).then(fn=get_latest_file, inputs=history_state, outputs=submit_button02, queue=False)
        submit_button41.click(user, [msg, chatbot, history_state], [msg, chatbot, history_state, gg1], queue=False).then(deepseekr1, [chatbot, history_state], [chatbot, history_state])
        clear_button42.click(tag, [history_state], [history_state, chatbot], queue=False)

    gr.Markdown("-----------------------------------------------------------")
    gr.Markdown("### 一个由中国的深度求索（DeepSeek）公司开发的智能助手DeepSeek-R1，采用稀疏化混合专家模型，通过人类反馈强化学习（RLHF）、对抗训练等技术对齐用户需求，具备较强的文本理解、推理和生成能力，尤其擅长中文场景。")
    gr.Markdown("-----------------------------------------------------------")
    gr.Markdown(f"> 原项目始部署于2024.2.8，本项目为精简独立模块，版本号：{ver}")
    gr.Markdown("> 桌面版运行于本机，网页版运行于服务器。使用老式Gradio框架，主要基于Python和HTML")
    gr.Markdown("> 作者信息：刘浩然 物理学院B8大厅18号桌 有事线下找我")
    css = "footer {visibility: hidden}"


demo.queue()
demo.launch(auth=mima, auth_message=dengluhtml, server_name="127.0.0.1", server_port=1234, share=False)
#  demo.launch(auth=mima, auth_message=dengluhtml, server_name="0.0.0.0", server_port=1234,share=False)